package com.skyinno.mrms.common.dao;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.hibernate.internal.CriteriaImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate4.HibernateCallback;
import org.springframework.orm.hibernate4.support.HibernateDaoSupport;

public class BaseDao extends HibernateDaoSupport {
    
	@Autowired
    public void setFactory(SessionFactory sessionFactory) {
        super.setSessionFactory(sessionFactory);
    }
	
	public List queryAll(final DetachedCriteria criteria) {
        return super.getHibernateTemplate().execute(
                new HibernateCallback<List>() {
                    /*
                     * (non-Javadoc)
                     * 
                     * @see org.springframework.orm.hibernate3.HibernateCallback#doInHibernate(org.hibernate.Session)
                     */
                    public List doInHibernate(Session session)
                            throws HibernateException {
                        CriteriaImpl criteriaImpl = (CriteriaImpl) criteria
                                .getExecutableCriteria(session);
                        if (criteriaImpl.getProjection() == null) {
                            criteria
                                    .setResultTransformer(CriteriaSpecification.ROOT_ENTITY);
                        }
                        return getHibernateTemplate().findByCriteria(criteria);
                    }
                });
    }

    public int queryCount(DetachedCriteria criteria) {
        criteria.setProjection(Projections.rowCount());
        List result = super.getHibernateTemplate().findByCriteria(criteria);
        criteria.setProjection(null);
        if (CollectionUtils.isNotEmpty(result)) {
            return ((Number) result.get(0)).intValue();
        }
        return 0;
    }

    public List queryPage(final DetachedCriteria criteria, final int start,
            final int pageSize) {
    	//hibernate升级   excute->executeWithNativeSession
    	//hibernate4中使用excute会导致SessionImplementor注入失败
        return super.getHibernateTemplate().executeWithNativeSession(
                new HibernateCallback<List>() {
                    /*
                     * (non-Javadoc)
                     * 
                     * @see org.springframework.orm.hibernate3.HibernateCallback#doInHibernate(org.hibernate.Session)
                     */
                    public List doInHibernate(Session session)
                            throws HibernateException {
                        CriteriaImpl criteriaImpl = (CriteriaImpl) criteria
                                .getExecutableCriteria(session);
                        if (criteriaImpl.getProjection() == null) {
                            criteria
                                    .setResultTransformer(CriteriaSpecification.ROOT_ENTITY);
                        }
                        return getHibernateTemplate().findByCriteria(criteria,
                                (start - 1) * pageSize, pageSize);
                    }
                });
    }
    /**
     * 根据开始结束点查询数据
     * @param criteria
     * @param start		开始
     * @param end		结束
     * @return
     */
    public List queryPageByLimit(final DetachedCriteria criteria, final int start,
            final int end) {
        return super.getHibernateTemplate().execute(
                new HibernateCallback<List>() {
                    /*
                     * (non-Javadoc)
                     * 
                     * @see org.springframework.orm.hibernate3.HibernateCallback#doInHibernate(org.hibernate.Session)
                     */
                    public List doInHibernate(Session session)
                            throws HibernateException {
                        CriteriaImpl criteriaImpl = (CriteriaImpl) criteria
                                .getExecutableCriteria(session);
                        if (criteriaImpl.getProjection() == null) {
                            criteria
                                    .setResultTransformer(CriteriaSpecification.ROOT_ENTITY);
                        }
                        return getHibernateTemplate().findByCriteria(criteria,
                                start - 1, end-start+1);
                    }
                });
    }

    public Serializable save(Object model) {
        return super.getHibernateTemplate().save(model);
    }

    public <T> T queryEntityById(Class<T> clz, Serializable id) {
        return (T) getHibernateTemplate().get(clz, id);
    }

    public void update(Object model) {
        super.getHibernateTemplate().merge(model);
    }

    public Integer execHqlUpdate(final String hql,
            final Map<String, Object> condition) {
        return super.getHibernateTemplate().execute(
                new HibernateCallback<Integer>() {
                    /*
                     * (non-Javadoc)
                     * 
                     * @see org.springframework.orm.hibernate3.HibernateCallback#doInHibernate(org.hibernate.Session)
                     */
                    public Integer doInHibernate(Session session)
                            throws HibernateException {
                        return createQuery(session, hql, condition)
                                .executeUpdate();
                    }
                });
    }

    private Query createQuery(Session session, String hql,
            Map<String, Object> condition) {
        Query query = session.createQuery(hql);
        return this.createQuery(query, condition);
    }

    private Query createQuery(Query query, Map<String, Object> condition) {
        if (MapUtils.isNotEmpty(condition)) {
            for (String key : condition.keySet()) {
                Object value = condition.get(key);
                if (value != null) {
                    if (Collection.class.isInstance(value)) {
                        query.setParameterList(key, (Collection) value);
                    } else if (value.getClass().isArray()) {
                        query.setParameterList(key, (Object[]) value);
                    } else {
                        query.setParameter(key, value);
                    }
                } else {
                    query.setParameter(key, value);
                }
            }
        }
        return query;
    }

//    public void saveOrUpdateAll(Collection collection) {
//        super.getHibernateTemplate().saveOrUpdateAll(collection);
//    }
    /**
     * TODO Bill 上面是以前的该方法，后来使用springboot自动加载spring4，
     * spring4里面已经删除了HibernateTemplate()的saveOrUpdateAll方法
     * 所以暂时用下面的代码替代，其实该方法肯定还有很多处理
     * @param collection
     */
    public void saveOrUpdateAll(Collection collection) {
    	for(Object entity : collection){
    		super.getHibernateTemplate().saveOrUpdate(entity);
    	}
    }

    public void saveOrUpdate(Object entity) {
        super.getHibernateTemplate().saveOrUpdate(entity);
    }

    public void deleteAll(Collection collection) {
        super.getHibernateTemplate().deleteAll(collection);
    }

    public void delete(Object obj) {
        super.getHibernateTemplate().delete(obj);
    }

    public int queryCountDistinct(DetachedCriteria criteria, String field) {
        criteria.setProjection(Projections.countDistinct(field));
        List result = super.getHibernateTemplate().findByCriteria(criteria);
        criteria.setProjection(null);
        if (CollectionUtils.isNotEmpty(result)) {
            return ((Number) result.get(0)).intValue();
        }
        return 0;
    }
    
    public int querySumField(DetachedCriteria criteria, String field) {
        criteria.setProjection(Projections.sum(field));
        List result = super.getHibernateTemplate().findByCriteria(criteria);
        criteria.setProjection(null);
        if (CollectionUtils.isNotEmpty(result)&&result.get(0)!=null) {
            return ((Number) result.get(0)).intValue();
        }
        return 0;
    }

    public List execHqlQuery(final String hql,
            final Map<String, Object> condition) {
        return super.getHibernateTemplate().execute(
                new HibernateCallback<List>() {
                    /*
                     * (non-Javadoc)
                     * 
                     * @see org.springframework.orm.hibernate3.HibernateCallback#doInHibernate(org.hibernate.Session)
                     */
                    public List doInHibernate(Session session)
                            throws HibernateException {
                        return createQuery(session, hql, condition).list();
                    }
                });
    }

    public List execSqlQuery(final String sql,
            final Map<String, Object> condition) {
        return super.getHibernateTemplate().execute(
                new HibernateCallback<List>() {
                    /*
                     * (non-Javadoc)
                     * 
                     * @see org.springframework.orm.hibernate3.HibernateCallback#doInHibernate(org.hibernate.Session)
                     */
                    public List doInHibernate(Session session)
                            throws HibernateException {
                        Query query = session.createSQLQuery(sql);
                        return createQuery(query, condition).list();
                    }
                });
    }

    /**
     * update
     * 
     * @param sql
     */
    @SuppressWarnings("unchecked")
    public void exeSqlUpdate(String sql) {
        final String tempsql = sql;
        super.getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session)
                    throws HibernateException {
                session.createSQLQuery(tempsql).executeUpdate();
                return null;
            }
        });
    }

    public List execHqlQueryPage(final String hql, final int start,
            final int pageSize, final Map<String, Object> condition) {
        return super.getHibernateTemplate().execute(
                new HibernateCallback<List>() {
                    /*
                     * (non-Javadoc)
                     * 
                     * @see org.springframework.orm.hibernate3.HibernateCallback#doInHibernate(org.hibernate.Session)
                     */
                    public List doInHibernate(Session session)
                            throws HibernateException {
                        return createQuery(session, hql, condition)
                                .setFirstResult((start - 1) * pageSize)
                                .setMaxResults(pageSize).list();
                    }
                });
    }
    
    
}
